import xml.dom.minidom
""" A Monkey-patch to xml.dom.minidon module """

def normalizeNamespace(self, namespaces={}):
	""" implements namespace normalization as described by
	http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html
	"""

	attrs = self._get_attributes()

	namespaces = namespaces.copy();

	# Pick up local namespace declarations
	for attribute in attrs.values():
		if attribute.prefix == "xmlns":
			if attribute.localName == "xmlns":
				# Note: The prefix xmlns is used only to declare namespace
				# bindings and is by definition bound to the namespace
				# name http://www.w3.org/2000/xmlns/. It must not be
				# declared. No other prefix may be bound to this
				# namespace name.
				raise xml.dom.NamespaceErr(
					"xmlns must not be declared")
			if attribute.value == xml.dom.XMLNS_NAMESPACE:
				raise xml.dom.NamespaceErr(
				   "no prefix can be bound to namespace %s " %
				   xml.dom.XMLNS_NAMESPACE)

			namespaces[attribute.localName] = attribute.value

		if attribute.prefix is None and attribute.localName == "xmlns":
			namespaces[None] = attribute.value

	# Fixup element's namespace

	if self.namespaceURI is not None:
		if namespaces.has_key(self.prefix) and \
			namespaces[self.prefix] == self.namespaceURI:

			# Element's prefix/namespace pair (or default namespace,
			# if no prefix) are within the scope of a binding )

			#  ==> do nothing, declaration in scope is inherited
			# See section "B.1.1: Scope of a binding" for an example
			pass
		else:
			# Create a local namespace declaration attr for this
			# namespace, with Element's current prefix (or a default
			# namespace, if no prefix). If there's a conflicting local
			# declaration already present, change its value to use this
			# namespace.

			# See section "B.1.2: Conflicting namespace declaration"
			# for an example

			#NOTE that this may break other nodes within this Element's
			# subtree, if they're already using this prefix.
			# They will be repaired when we reach them.
			if self.prefix is None:
				self.setAttribute("xmlns",
									self.namespaceURI)
			else:
				self.setAttributeNS(xml.dom.XMLNS_NAMESPACE,
									"xmlns:%s" % self.prefix,
									self.namespaceURI)
			namespaces[self.prefix] = self.namespaceURI
	else:
		# Element has no namespace URI:
		if self.localName is None:
		   # DOM Level 1 node
		   # if in process of validation against a namespace aware schema
		   # (i.e XML Schema) report a fatal error: the
		   # processor can not recover
		   # in this situation.
		   # Otherwise, report an error:
		   # no namespace fixup will be performed on this node.
		   raise xml.dom.NamespaceErr("Node must have a local name")
		elif namespaces.has_key(None):
		  # Element has no pseudo-prefix

		  #there's a conflicting local default namespace declaration
		  #     already present )
		  # change its value to use this empty namespace.
		  # NOTE that this may break other nodes within this Element's
		  # subtree, if they're already using the default namespaces.
		  # They will be repaired when we reach them.
		  del namespaces[None]

		  if self.hasAttribute("xmlns"):
		      self.removeAttribute("xmlns")


	# Examine and polish the attributes

	for attribute in attrs.values():
		if attribute.prefix == "xmlns":
			continue;
		if attribute.name == "xmlns":
			continue;


		if attribute.namespaceURI is not None:

			if attribute.prefix is None or \
				not self.hasAttributeNS(xml.dom.XMLNS_NAMESPACE,
										attribute.prefix) or \
				( namespaces.has_key(attribute.prefix) and \
				  namespaces[attribute.prefix] != attribute.namespaceURI):
				matched = False;

				# pick the most local binding available;
				# if there is more than one pick one arbitrarily
				# ==> change attribute's prefix.
				for (key, value) in namespaces.items():
					if value == attribute.namespaceURI:
						matched = True;
						self.removeAttributeNode(attribute)
						if key is None:
							self.setAttributeNS(attribute.namespaceURI,
								"%s" % attribute.localName,
								attribute.value)
						else:
							self.setAttributeNS(attribute.namespaceURI,
								"%s:%s" % (key , attribute.localName ),
								attribute.value)

						break;

				if matched:
					pass;
				elif (attribute.prefix is not None and \
					not self.hasAttributeNS(xml.dom.XMLNS_NAMESPACE,
											attribute.prefix)):

					self.setAttributeNS(xml.dom.XMLNS_NAMESPACE,
								"xmlns:%s" % attribute.prefix,
								attribute.namespaceURI)
					namespaces[attribute.prefix] = attribute.namespaceURI
				else:
					# find a prefix following the pattern "NS" +index
					# (starting at 1)
					# make sure this prefix is not declared in the current
					# scope.
					# create a local namespace declaration attribute
					# ==> change attribute's prefix.
					index = 1
					while namespaces.has_key("NS%d" %index):
						index+=1;

					prefix = "NS%d" %index

					self.setAttributeNS(xml.dom.XMLNS_NAMESPACE,
								"xmlns:%s" % prefix,
								attribute.namespaceURI)

					namespaces[prefix] = attribute.namespaceURI

					self.removeAttributeNode(attribute)
					self.setAttributeNS(attribute.namespaceURI,
							  "%s:%s" % (prefix , attribute.localName ),
							  attribute.value)
		else:
			# Attr[i] has no namespace URI

			if ( attribute.localName is None ):
			   # DOM Level 1 node
			   # ==> if in process of validation against a
			   # namespace aware schema
			   #    (i.e XML Schema) report a fatal error:
			   # the processor can not recover
			   #     in this situation.
			   #     Otherwise, report an error: no namespace
			   # fixup will be performed on this node.
			   raise xml.dom.NamespaceErr("Attribute must have a name")
			else:
			   # attr has no namespace URI and no prefix
			   # no action is required, since attrs don't use default
			   #    ==> do nothing
			   pass

	# do this recursively
	for childNode in self.childNodes:
		if childNode.nodeType == childNode.ELEMENT_NODE:
			childNode.normalizeNamespace(namespaces)

def writexml(self, writer, indent="", addindent="", newl="",
			 encoding = None):
	if encoding is None:
		writer.write('<?xml version="1.0" ?>'+newl)
	else:
		writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))
	for node in self.childNodes:
		if node.nodeType == node.ELEMENT_NODE:
			node.normalizeNamespace()
		node.writexml(writer, indent, addindent, newl)

# If patch isn't still implemented
if(not hasattr(xml.dom.minidom.Element, 'normalizeNamespace')):
	xml.dom.minidom.Document.writexml = writexml
	xml.dom.minidom.Element.normalizeNamespace = normalizeNamespace
#	setattr(xml.dom.minidom.Document, 'writexml', writexml)
#	setattr(xml.dom.minidom.Element, 'normalizeNamespace', normalizeNamespace)
#new_dom = xml.dom.minidom
